/* 
 * Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *      * The names of its contributors may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package kameleon.gui;

import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import kameleon.exception.KameleonException;
import kameleon.gui.exception.UnknownKeyException;
import kameleon.gui.language.GuiLanguage;
import kameleon.gui.language.SwitchLanguage;
import kameleon.gui.util.GuiWorkSpaceManager;
import kameleon.gui.util.LanguageConstants;
import kameleon.gui.view.MainFrame;
import kameleon.plugin.PlugInManager;
import kameleon.util.WorkSpaceManager;

/**
 * Entry point for the Kameleon software.
 *
 * @author	Schnell Michaël
 * @version	1.0
 */
public class Main implements LanguageConstants, ArgumentConstants {

    /**
     * //TODO Review Default language used by the software.
     */
    private static final GuiLanguage DEFAULT_LANGUAGE = GuiLanguage.ENGLISH;
    /**
     * Flag for the debug mode ({@code true} means activated).
     */
    protected boolean debugMode;

    /**
     * Entry point for the Kameleon software.
     *
     * @param args command line arguments
     */
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        new Main(args);
    }// main(String[])

    /**
     * Sole constructor.
     *
     * @param args command line arguments
     */
    public Main(String[] args) {
        super();
        try {
            this.checkArgs(args);
        } catch (KameleonException ke) {
            this.displayErrorMessage(ke);
        }// if
    }// Main(String[])

    /**
     * Subclass of {@code Runnable} which launches the graphical interface of
     * the Kameleon software. If the launch fails, a pop-up window is displayed.
     *
     * @author	Schnell Michaël
     * @version	1.0
     */
    private class GuiRunnable implements Runnable {

        /**
         * Used to access command line arguments.
         */
        private Main main;

        /**
         * Sole constructor.
         *
         * @param main instance containing the command line arguments
         */
        public GuiRunnable(Main main) {
            super();
            this.main = main;
        }// GuiRunnable(Main)

        /**
         * Launches the graphical interface of the Kameleon software. If the
         * launch fails, a pop-up window is displayed.
         */
        @Override
        public void run() {
            try {
                GuiWorkSpaceManager.ensureBaseLanguage();
                SwitchLanguage.initialize();
                MainFrame gui = new MainFrame(this.main.debugMode);
                gui.setVisible(true);
            } catch (KameleonException ke) {
                this.main.displayErrorMessage(ke);
            }// try
        }// run()
    }// class GuiRunnable

    /**
     * Checks if the given command line arguments are correct and retrieves
     * their values for later use.
     *
     * @param args command line arguments
     *
     * @return	{@code true} if the arguments are valid and their values have
     * been successfully retrieved, {@code false} otherwise
     */
    private void checkArgs(String[] args) throws KameleonException {
        // Set default debug mode
        this.debugMode = PlugInManager.DEFAULT_DEBUG_MODE;
        boolean launchGui = true;

        int nArgs = args.length;
        for (int i = 0; i < nArgs; ++i) {
            if (args[i].equals(Argument.DEBUG.getValue())) {
                this.debugMode = true;
            }// if
            else if (args[i].equals(Argument.PLUGIN.getValue()) && nArgs > i + Argument.PLUGIN.getnParameters()) {
                launchGui = false;
                PlugInManager pm = new PlugInManager(this.debugMode);

                WorkSpaceManager.ensureWorkSpace();
                pm.addPlugIn(args[i + 1]);
                i++ ;
            } else {
                // display usage
                launchGui = false;
                Main.displayUsage();
            }// if
        }// for

        if (launchGui) {
            SwingUtilities.invokeLater(new GuiRunnable(this));
        }// if
    }// checkArgs(String[])

    /**
     * Displays a pop-up window to alert the user that the software has crashed.
     *
     * <p>The error message will be displayed in the language defined by the
     * user or in the default language. If the debug mode is activated, detailed
     * information about the error is shown.
     *
     * @param ke exception which caused the software to crash
     */
    protected void displayErrorMessage(KameleonException ke) {
        SwitchLanguage sl = SwitchLanguage.getInstance();
        String message = null;
        String title = null;

        // Build the title and message of the pop-up
        try {
            sl.getText(MAN_GUI_ERROR_MESSAGE_TITLE);
            if (this.debugMode) {
                message = sl.getText(MAIN_GUI_DETAILED_ERROR_MESSAGE,
                        ke.getClass(),
                        ke.getMessage(),
                        KameleonException.getStackTraceAsString(ke));
            } else {
                message = sl.getText(MAIN_GUI_ERROR_MESSAGE);
            }// if
        } catch (UnknownKeyException uke) {
            // Incorrect language file, switch to default
            try {
                sl.changeLang(DEFAULT_LANGUAGE);
                sl.getText(MAN_GUI_ERROR_MESSAGE_TITLE);
                if (this.debugMode) {
                    message = sl.getText(MAIN_GUI_ERROR_MESSAGE);
                } else {
                    message = sl.getText(MAIN_GUI_DETAILED_ERROR_MESSAGE,
                            ke.getClass(),
                            ke.getMessage(),
                            KameleonException.getStackTraceAsString(ke));
                }// if
            } catch (KameleonException ke2) {/*
                 * This should not happen.
                 */

            }// try
        }// try

        JOptionPane.showMessageDialog(null, message, title, JOptionPane.ERROR_MESSAGE);
    }// displayErrorMessage(KameleonException)

    /**
     * Displays the usage of the Kameleon command.
     */
    private static void displayUsage() {
        String arguments;
        //TODO Remove hard coded message
        System.out.println("Invalid arguments."); //$NON-NLS-1$

        arguments = String.format("[%s] [%s <plug-in path>]", //$NON-NLS-1$
                Argument.DEBUG.getValue(), Argument.PLUGIN.getValue());
        System.out.printf("     : java -jar <path to>%sKameleon.jar %s\n\n", //$NON-NLS-1$
                File.separator, arguments);
    }// displayUsage()
}// class Main